package appmgr;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import socket.*;
import struct.*;
import struct.enums.SensorMode;
import struct.SensorInfo;
import struct.ServiceInfo;
import struct.sync.SynchronousString;
import util.Util;
import pubsub.Channel;
import resource.ActorMgr;
import resource.ResMgrThread;
import resource.SensorMgr;
import pubsub.AbstractSubscriber;
import pubsub.Publisher;
import struct.enums.CmdType;
import struct.enums.ServiceType;
import database.Condition;
import database.Order;
import service.inv.AppInvServer;
import service.inv.PlatformInvServer;
import webserver.JSPMaker;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.nio.file.Path;
import java.util.*;

import static sepal.Sepal.call;
import static socket.CmdMessage.CMD_FIELD;

public class AppDriver extends AbstractSubscriber implements Runnable {
    private TCP tcp;
    private String clientIP = null;
    private int clientUDPPort = -1;
    private int grpId = -1;
    private boolean getMsgThreadState = false;
    private AppMgr appMgr = null;
    private final SynchronousString _getSensorData = new SynchronousString();
    private final SynchronousString _setActorCmd = new SynchronousString();

    private static final String SUCCESS_STATE = "{\"state\":true}";
    private static final String FAIL_STATE = "{\"state\":false}";
    private static final String GET_SENSOR_DATA = "getSensorData";

    public AppDriver(Socket socket) {
        this.tcp = new AppDriverTCP(socket, false);
    }

    public String getClientIP() {
        return clientIP;
    }

    public int getClientUDPPort() {
        return clientUDPPort;
    }

    public class AppDriverTCP extends AbstractTCP {
        public AppDriverTCP(Socket socket, boolean lockFlag) {
            super(socket, lockFlag);
        }

        public AppDriverTCP(Socket socket) {
            super(socket);
        }

        @Override
        public void close() {
            try {
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            disConnectPlatform();
        }

        @Override
        public void callback() {
            String name = "AppDriver";
            if (appMgr != null) {
                name = appMgr.getAppName();
            }
            logger.error(String.format("[%s]: TCP connection is broken. Start releasing app resources...", name));
            if (disConnectPlatform().equals(SUCCESS_STATE)) {
                logger.info(String.format("[%s]: App resource released successfully.", name));
            } else {
                logger.error(String.format("[%s]: App resource released failed.", name));
            }
        }
    }

    @Override
    public void run() {
        String msgFromClient;
        while ((msgFromClient = tcp.recv()) != null) {
            JSONObject jo = JSON.parseObject(msgFromClient);
            if (appMgr != null) {
                logger.info(String.format("[%s -> Platform]: %s", appMgr.getAppName(), msgFromClient));
            } else {
                logger.info(String.format("[AppDriver -> Platform]: %s", msgFromClient));
            }

            String api = jo.getString(DataField.API_FIELD);
            String ret = null;
            try {
                if (api == null) {

                } else if (api.equalsIgnoreCase(ProtocolMessage.CONNECT_PLATFORM)) {
                    ret = connectPlatform();
                } else if (api.equalsIgnoreCase(ProtocolMessage.DISCONNECT_PLATFORM)) {
                    ret = disConnectPlatform();
                } else if (api.equalsIgnoreCase(ProtocolMessage.CHECK_CONNECTED)) {
                    ret = checkConnect();
                } else if (api.equalsIgnoreCase(ProtocolMessage.REGISTER_APP)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = registerApp(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.UNREGISTER_APP)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = unregisterApp(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_SUPPORTED_SENSORS)) {
                    ret = getSupportedSensors();
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_REGISTERED_SENSORS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getRegisteredSensors(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_REGISTERED_SENSORS_STATUS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getRegisteredSensorsStatus(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.REGISTER_SENSOR)) {
                    String sensorName = jo.getString(SensorInfo.SENSOR_NAME_FIELD);
                    SensorMode mode = SensorMode.fromString(jo.getString(DataField.MODE_FIELD));
                    int freq = jo.getIntValue(DataField.FREQ_FIELD);
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = registerSensor(appName, sensorName, mode, freq);
                } else if (api.equalsIgnoreCase(ProtocolMessage.CANCEL_SENSOR)) {
                    String sensorName = jo.getString(SensorInfo.SENSOR_NAME_FIELD);
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = cancelSensor(appName, sensorName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.CANCEL_ALL_SENSORS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = cancelAllSensors(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_SENSOR_DATA)) {
                    String sensorName = jo.getString(SensorInfo.SENSOR_NAME_FIELD);
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getSensorData(appName, sensorName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_ALL_SENSOR_DATA)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getAllSensorData(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_MSG_THREAD)) {
                    CmdType cmd = CmdType.fromString(jo.getString(CMD_FIELD));
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getMsgThread(appName, cmd);
                }else if (api.equalsIgnoreCase(ProtocolMessage.GET_SUPPORTED_ACTORS)) {
                    ret = getSupportedActors();
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_REGISTERED_ACTORS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getRegisteredActors(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_REGISTERED_ACTORS_STATUS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getRegisteredActorsStatus(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.REGISTER_ACTOR)) {
                    String actorName = jo.getString(ActorInfo.ACTOR_NAME_FIELD);
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret =  registerActor(appName, actorName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.CANCEL_ACTOR)) {
                    String actorName = jo.getString(ActorInfo.ACTOR_NAME_FIELD);
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = cancelActor(appName, actorName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.CANCEL_ALL_ACTORS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = cancelAllActors(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.SEND_ACTOR_CMD)) {
                    String actorName = jo.getString(ActorInfo.ACTOR_NAME_FIELD);
                    String action = jo.getString(DataField.ACTION_FIELD);
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = setActorCmd(appName, actorName, action);
                } else if (api.equalsIgnoreCase(ProtocolMessage.IS_SERVICE_ON)) {
                    ServiceType service = ServiceType.fromString(jo.getString(ServiceInfo.SERVICE_TYPE_FIELD));
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = isServiceOn(appName, service);
                } else if (api.equalsIgnoreCase(ProtocolMessage.SERVICE_START)) {
                    ServiceType service = ServiceType.fromString(jo.getString(ServiceInfo.SERVICE_TYPE_FIELD));
                    ServiceConfig config = null;
                    try {
                        if (service == ServiceType.CTX) {
                            config = CtxServiceConfig.fromJSONString(jo.getString(ServiceInfo.SERVICE_CONFIG_FIELD));
                        } else {
                            config = InvServiceConfig.fromJSONString(jo.getString(ServiceInfo.SERVICE_CONFIG_FIELD));
                        }
                    } catch (Exception ignored) {}
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = serviceCall(appName, service, CmdType.START, config);
                } else if (api.equalsIgnoreCase(ProtocolMessage.SERVICE_STOP)) {
                    ServiceType service = ServiceType.fromString(jo.getString(ServiceInfo.SERVICE_TYPE_FIELD));
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = serviceCall(appName, service, CmdType.STOP, null);
                } else if (api.equalsIgnoreCase(ProtocolMessage.SERVICE_CALL)) {
                    ServiceType service = ServiceType.fromString(jo.getString(ServiceInfo.SERVICE_TYPE_FIELD));
                    CmdType cmd = CmdType.fromString(jo.getString(DataField.CMD_TYPE_FIELD));
                    ServiceConfig config = null;
                    try {
                        if (service == ServiceType.CTX) {
                            config = CtxServiceConfig.fromJSONString(jo.getString(ServiceInfo.SERVICE_CONFIG_FIELD));
                        } else {
                            config = InvServiceConfig.fromJSONString(jo.getString(ServiceInfo.SERVICE_CONFIG_FIELD));
                        }
                    } catch (Exception ignored) {}
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = serviceCall(appName, service, cmd, config);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_SENSOR_INFO)) {
                    String sensorName = jo.getString(SensorInfo.SENSOR_NAME_FIELD);
                    ret = getSensorInfo(sensorName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_SENSOR_INFO_AND_DATA)) {
                    String sensorName = jo.getString(SensorInfo.SENSOR_NAME_FIELD);
                    ret = getSensorInfoAndData(sensorName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_ALL_SENSOR_INFO)) {
                    ret = getSupportedSensors();
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_ALL_SENSOR_INFO_AND_DATA)) {
                    ret = getAllSensorInfoAndData();
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_ACTOR_INFO)) {
                    String actorName = jo.getString(ActorInfo.ACTOR_NAME_FIELD);
                    ret = getActorInfo(actorName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_ALL_ACTOR_INFO)) {
                    ret = getSupportedActors();
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_APP_INFO)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ret = getAppInfo(appName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_ALL_APP_INFO)) {
                    ret = getAllAppInfo();
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_SERVICE_INFO)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    ServiceType service = ServiceType.fromString(jo.getString(ServiceInfo.SERVICE_TYPE_FIELD));
                    ret = getServiceInfo(appName, service);
                } else if (api.equalsIgnoreCase(ProtocolMessage.GET_ALL_SERVICE_INFO)) {
                    ServiceType service = ServiceType.fromString(jo.getString(ServiceInfo.SERVICE_TYPE_FIELD));
                    ret = getAllServiceInfo(service);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_CREATE)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    String primaryKey = jo.getString(DataField.PRIM_KEY_FIELD);
                    int rowLimit = jo.getIntValue(DataField.ROW_LIMIT_FIELD);
                    List<String> header = jo.getJSONArray(DataField.HEADER_FIELD).toJavaList(String.class);
                    ret = dbCreate(appName, tableName, primaryKey, header, rowLimit);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_DROP)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    ret = dbDrop(appName, tableName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_INSERT)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    JSONObject rowJson = jo.getJSONObject(DataField.ROW_FIELD);
                    Map<String, Object> row = new LinkedHashMap<>(rowJson);
                    ret = dbInsert(appName, tableName, row);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_INSERTS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    JSONArray rowsJson = jo.getJSONArray(DataField.ROW_FIELD);
                    ret = "{\"state\": false}";
                    if (rowsJson != null) {
                        int i;
                        for (i = 0; i < rowsJson.size(); i++) {
                            if (dbInsert(appName, tableName, new LinkedHashMap<>(rowsJson.getJSONObject(i))).equalsIgnoreCase("{\"state\": false}")) {
                                break;
                            }
                        }
                        if (i == rowsJson.size()) {
                            ret = "{\"state\": true}";
                        }
                    }
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_UPDATE)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    JSONObject rowJson = jo.getJSONObject(DataField.ROW_FIELD);
                    Map<String, Object> row = new LinkedHashMap<>(rowJson);
                    ret = dbUpdate(appName, tableName, row);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_DELETE)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    int row = jo.getIntValue(DataField.ROW_FIELD);
                    JSONArray conditionsJson = jo.getJSONArray("conditions");
                    List<Condition> conditions;
                    if (conditionsJson == null) {
                        conditions = null;
                    } else {
                        conditions = new ArrayList<>();
                        for (int i = 0; i < conditionsJson.size(); i++) {
                            conditions.add(new Condition(conditionsJson.getJSONObject(i)));
                        }
                    }
                    JSONArray ordersJson = jo.getJSONArray("orders");
                    List<Order> orders;
                    if (ordersJson == null) {
                        orders = null;
                    } else {
                        orders = new ArrayList<>();
                        for (int i = 0; i < ordersJson.size(); i++) {
                            orders.add(new Order(ordersJson.getJSONObject(i)));
                        }
                    }
                    ret = dbDelete(appName, tableName, row, conditions, orders);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_DELETES)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    int rows = jo.getIntValue(DataField.ROWS_FIELD);
                    JSONArray conditionsJson = jo.getJSONArray("conditions");
                    List<Condition> conditions;
                    if (conditionsJson == null) {
                        conditions = null;
                    } else {
                        conditions = new ArrayList<>();
                        for (int i = 0; i < conditionsJson.size(); i++) {
                            conditions.add(new Condition(conditionsJson.getJSONObject(i)));
                        }
                    }
                    JSONArray ordersJson = jo.getJSONArray("orders");
                    List<Order> orders;
                    if (ordersJson == null) {
                        orders = null;
                    } else {
                        orders = new ArrayList<>();
                        for (int i = 0; i < ordersJson.size(); i++) {
                            orders.add(new Order(ordersJson.getJSONObject(i)));
                        }
                    }
                    ret = dbDeletes(appName, tableName, rows, conditions, orders);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_ROW)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    int row = jo.getIntValue(DataField.ROW_FIELD);
                    JSONArray columnsJson = jo.getJSONArray("columns");
                    List<String> columns;
                    if (columnsJson == null) {
                        columns = null;
                    } else {
                        columns = new ArrayList<>();
                        for (int i = 0; i < columnsJson.size(); i++) {
                            columns.add(columnsJson.getString(i));
                        }
                    }
                    JSONArray conditionsJson = jo.getJSONArray("conditions");
                    List<Condition> conditions;
                    if (conditionsJson == null) {
                        conditions = null;
                    } else {
                        conditions = new ArrayList<>();
                        for (int i = 0; i < conditionsJson.size(); i++) {
                            conditions.add(new Condition(conditionsJson.getJSONObject(i)));
                        }
                    }
                    JSONArray ordersJson = jo.getJSONArray("orders");
                    List<Order> orders;
                    if (ordersJson == null) {
                        orders = null;
                    } else {
                        orders = new ArrayList<>();
                        for (int i = 0; i < ordersJson.size(); i++) {
                            orders.add(new Order(ordersJson.getJSONObject(i)));
                        }
                    }
                    ret = dbRow(appName, tableName, row, columns, conditions, orders);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_ROWS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    int rows = jo.getIntValue(DataField.ROWS_FIELD);
                    JSONArray columnsJson = jo.getJSONArray("columns");
                    List<String> columns;
                    if (columnsJson == null) {
                        columns = null;
                    } else {
                        columns = new ArrayList<>();
                        for (int i = 0; i < columnsJson.size(); i++) {
                            columns.add(columnsJson.getString(i));
                        }
                    }
                    JSONArray conditionsJson = jo.getJSONArray("conditions");
                    List<Condition> conditions;
                    if (conditionsJson == null) {
                        conditions = null;
                    } else {
                        conditions = new ArrayList<>();
                        for (int i = 0; i < conditionsJson.size(); i++) {
                            conditions.add(new Condition(conditionsJson.getJSONObject(i)));
                        }
                    }
                    JSONArray ordersJson = jo.getJSONArray("orders");
                    List<Order> orders;
                    if (ordersJson == null) {
                        orders = null;
                    } else {
                        orders = new ArrayList<>();
                        for (int i = 0; i < ordersJson.size(); i++) {
                            orders.add(new Order(ordersJson.getJSONObject(i)));
                        }
                    }
                    ret = dbRows(appName, tableName, rows, columns, conditions, orders);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_COLUMN)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    int rows = jo.getIntValue(DataField.ROWS_FIELD);
                    String column = jo.getString("column");
                    JSONArray conditionsJson = jo.getJSONArray("conditions");
                    List<Condition> conditions;
                    if (conditionsJson == null) {
                        conditions = null;
                    } else {
                        conditions = new ArrayList<>();
                        for (int i = 0; i < conditionsJson.size(); i++) {
                            conditions.add(new Condition(conditionsJson.getJSONObject(i)));
                        }
                    }
                    JSONArray ordersJson = jo.getJSONArray("orders");
                    List<Order> orders;
                    if (ordersJson == null) {
                        orders = null;
                    } else {
                        orders = new ArrayList<>();
                        for (int i = 0; i < ordersJson.size(); i++) {
                            orders.add(new Order(ordersJson.getJSONObject(i)));
                        }
                    }
                    ret = dbColumn(appName, tableName, rows, column, conditions, orders);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_COLUMNS)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    int rows = jo.getIntValue(DataField.ROWS_FIELD);
                    JSONArray columnsJson = jo.getJSONArray("columns");
                    List<String> columns;
                    if (columnsJson == null) {
                        columns = null;
                    } else {
                        columns = new ArrayList<>();
                        for (int i = 0; i < columnsJson.size(); i++) {
                            columns.add(columnsJson.getString(i));
                        }
                    }
                    JSONArray conditionsJson = jo.getJSONArray("conditions");
                    List<Condition> conditions;
                    if (conditionsJson == null) {
                        conditions = null;
                    } else {
                        conditions = new ArrayList<>();
                        for (int i = 0; i < conditionsJson.size(); i++) {
                            conditions.add(new Condition(conditionsJson.getJSONObject(i)));
                        }
                    }
                    JSONArray ordersJson = jo.getJSONArray("orders");
                    List<Order> orders;
                    if (ordersJson == null) {
                        orders = null;
                    } else {
                        orders = new ArrayList<>();
                        for (int i = 0; i < ordersJson.size(); i++) {
                            orders.add(new Order(ordersJson.getJSONObject(i)));
                        }
                    }
                    ret = dbColumns(appName, tableName, rows, columns, conditions, orders);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_CELL)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    int row = jo.getIntValue(DataField.ROW_FIELD);
                    String column = jo.getString("column");
                    JSONArray conditionsJson = jo.getJSONArray("conditions");
                    List<Condition> conditions;
                    if (conditionsJson == null) {
                        conditions = null;
                    } else {
                        conditions = new ArrayList<>();
                        for (int i = 0; i < conditionsJson.size(); i++) {
                            conditions.add(new Condition(conditionsJson.getJSONObject(i)));
                        }
                    }
                    JSONArray ordersJson = jo.getJSONArray("orders");
                    List<Order> orders;
                    if (ordersJson == null) {
                        orders = null;
                    } else {
                        orders = new ArrayList<>();
                        for (int i = 0; i < ordersJson.size(); i++) {
                            orders.add(new Order(ordersJson.getJSONObject(i)));
                        }
                    }
                    ret = dbCell(appName, tableName, row, column, conditions, orders);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_HEADER)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    ret = dbHeader(appName, tableName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.DB_COUNT)) {
                    String appName = jo.getString(AppInfo.APP_NAME_FIELD);
                    String tableName = jo.getString(DataField.TABLE_NAME_FIELD);
                    ret = dbCount(appName, tableName);
                } else if (api.equalsIgnoreCase(ProtocolMessage.INV_MONITOR)) {
                    ret = monitor(jo.getString(AppInfo.APP_NAME_FIELD), jo.getJSONArray("objs"));
                } else if (api.equalsIgnoreCase(ProtocolMessage.INV_IS_MONITORED)) {
                    ret = isMonitored(jo.getString(AppInfo.APP_NAME_FIELD), jo.getJSONArray("objs"));
                } else if (api.equalsIgnoreCase(ProtocolMessage.INV_CHECK)) {
                    ret = check(jo.getString(AppInfo.APP_NAME_FIELD), jo);
                } else if (api.equalsIgnoreCase(ProtocolMessage.INV_SAVE)) {
                    ret = save(jo.getString(AppInfo.APP_NAME_FIELD));
                } else if (api.equalsIgnoreCase(ProtocolMessage.INV_LOAD)) {
                    ret = load(jo.getString(AppInfo.APP_NAME_FIELD), jo.getString("content"));
                } else if (api.equalsIgnoreCase(ProtocolMessage.INV_CHECK_GENERATED)) {
                    ret = checkGenerated(jo.getString(AppInfo.APP_NAME_FIELD));
                } else if (api.equalsIgnoreCase(ProtocolMessage.SET_UI)) {
                    ret = setUI(jo.getString(DataField.JSP_URL_FIELD), jo.getString(DataField.DSL_FIELD));
                }
            } catch (Exception e) {
                logger.error(msgFromClient + " -> " + e.getMessage());
            }
            tcp.send(ret);
            if (appMgr != null) {
                logger.info(String.format("[Platform -> %s]: %s", appMgr.getAppName(), ret));
            } else {
                logger.info(String.format("[Platform -> AppDriver]: %s", ret));
            }
            if (api.equalsIgnoreCase(ProtocolMessage.DISCONNECT_PLATFORM)) {
                break;
            }
        }
        tcp.close();
    }

    @Override
    public void onMessage(String channel, String msg) {
        String flag = appMgr.getRequestMap().get(channel).nonBlockTake();
        if (flag.equalsIgnoreCase(GET_SENSOR_DATA)) {
            _getSensorData.put(msg);
        } else if (flag.equalsIgnoreCase("invGetSensorData")) {
            appMgr.getInvServer().getInvGetSensorData().put(SensorData.fromJSONString(msg));
        } else if (flag.equalsIgnoreCase("passiveGetSensorData")) {
            JSONObject jo = new JSONObject(2);
            jo.put("channel", channel);
            jo.put("msg", msg);
            UDP.send(clientIP, clientUDPPort, jo.toJSONString());
            logger.info(String.format("[Platform -> %s][UDP]: %s", appMgr.getAppName(), jo.toJSONString()));
        } else if (flag.equalsIgnoreCase("setActorCmd")) {
            _setActorCmd.put(msg);
        }
    }

    private String connectPlatform() {
        JSONObject retJson = new JSONObject(1);
        retJson.put(DataField.STATE_FIELD, true);
        return retJson.toJSONString();
    }

    private String disConnectPlatform() {
        String ret = SUCCESS_STATE;
        if (appMgr != null) {
            ret = unregisterApp(appMgr.getAppName());
        }
        return ret;
    }

    private String checkConnect() {
        JSONObject retJson = new JSONObject(1);
        if (appMgr != null) {
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String registerApp(String appName) {
        JSONObject retJson = new JSONObject(2);
        if (appMgr == null) {
            clientIP = tcp.getSocket().getInetAddress().getHostAddress();
            clientUDPPort = AppMgrThread.getNewPort(tcp.getSocket());
            grpId = AppMgrThread.getNewGrpId(appName);
            appMgr = new AppMgr(appName);
            appMgr.setGrpId(grpId);
            appMgr.setAppDriver(this);
            AppMgrThread.getAppMgrs().put(appName, appMgr);
            retJson.put(DataField.STATE_FIELD, true);
            retJson.put(DataField.PORT_FIELD, clientUDPPort);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String unregisterApp(String appName) {
        JSONObject retJson = new JSONObject(1);
        if (appMgr != null && appMgr.getAppName().equalsIgnoreCase(appName)) {
            cancelAllSensors(appName);
            cancelAllActors(appName);
            AppMgrThread.getAppMgrs().remove(appName);
            appMgr.removeDatabase();
            appMgr = null;
            AppMgrThread.removePort(tcp.getSocket(), clientUDPPort);
            clientIP = null;
            clientUDPPort = -1;
            getMsgThreadState = false;
            // TODO:还有剩余资源待释放
            serviceCall(appName, ServiceType.ALL, CmdType.STOP, null);
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String getSupportedSensors() {
        JSONArray retJsonArray = new JSONArray();
        ResMgrThread.getSensorMgrs().forEach((sensorName, config) -> {
            retJsonArray.add(JSONObject.parse(config.toString()));
        });
        return retJsonArray.toJSONString();
    }

    private String getRegisteredSensors(String appName) {
        JSONArray retJsonArray = new JSONArray();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            appMgr.getSensors().forEach(config -> {
                retJsonArray.add(JSONObject.parse(config.toString()));
            });
        }
        return retJsonArray.toJSONString();
    }

    private String getRegisteredSensorsStatus(String appName) {
        JSONObject retJson = new JSONObject(1);
        boolean status = true;
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            for (SensorMgr config : appMgr.getSensors()) {
                if (!config.isAlive()) {
                    status = false;
                    break;
                }
            }
        } else {
            status = false;
        }
        retJson.put(DataField.STATE_FIELD, status);
        return retJson.toJSONString();
    }

    private void _registerSensor(String appName, String sensorName, SensorMode mode, int freq) {
        SensorMgr sensorMgr = ResMgrThread.getSensorMgrs().get(sensorName);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if(appMgr.addSensor(sensorMgr)){
            sensorMgr.getApps().add(appMgr);
            subscribe(Channel.getSensor(sensorName), grpId);
        }

        synchronized (sensorMgr.getTimeLine()) {
            if (mode == SensorMode.ACTIVE) {
                sensorMgr.getTimeLine().deleteAppName(appMgr.getAppName(), freq);
            } else {
                sensorMgr.getTimeLine().insertAppName(appMgr.getAppName(), freq);
            }
            if (sensorMgr.getTimeLine().size() != 0) {
                sensorMgr.getTimeLine().notify();
            }
        }
    }

    private String registerSensor(String appName, String sensorName, SensorMode mode, int freq) {
        JSONObject retJson = new JSONObject(1);
        Map<String, SensorMgr> sensorMgrMap = ResMgrThread.getSensorMgrs();
        SensorMgr sensorMgr = sensorMgrMap.get(sensorName);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null
                && sensorMgrMap.containsKey(sensorName)
                && ((mode == SensorMode.ACTIVE && freq == -1) ||
                (mode == SensorMode.PASSIVE && sensorMgr.checkValueFreq(freq)))) {
            _registerSensor(appName, sensorName, mode, freq);
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    public void _cancelSensor(String appName, String sensorName) {
        SensorMgr sensorMgr = ResMgrThread.getSensorMgrs().get(sensorName);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if(appMgr.removeSensor(sensorMgr)){
            sensorMgr.getApps().remove(appMgr);
            if (sensorMgr.getApps().size() == 0) {
                //TODO:可能有死锁
                sensorMgr.stopGetValue();
            }
            unsubscribe(Channel.getSensor(sensorName));
        }

        synchronized (sensorMgr.getTimeLine()) {
            if (sensorMgr.getTimeLine().getAppName2Freq().containsKey(appMgr.getAppName())) {
                int freq = sensorMgr.getTimeLine().getAppName2Freq().get(appMgr.getAppName());
                sensorMgr.getTimeLine().deleteAppName(appMgr.getAppName(), freq);
                sensorMgr.getTimeLine().getAppName2Freq().remove(appMgr.getAppName());
            }
        }
    }

    private String cancelSensor(String appName, String sensorName) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null && appMgr.getSensorsName().contains(sensorName)) {
            _cancelSensor(appName, sensorName);
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String cancelAllSensors(String appName) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            appMgr.getSensorsName().forEach(sensorName -> {
                cancelSensor(appName, sensorName);
            });
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String getSensorData(String appName, String sensorName) {
        String value = "{\"default\":\"@#$%\"}";
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null && appMgr.getAppName().equals("WebServer") && !appMgr.getSensorsName().contains(sensorName)) {
            registerSensor(appName, sensorName, SensorMode.ACTIVE, -1);
        }
        if (appMgr != null
                && appMgr.getSensorsName().contains(sensorName)
                && ResMgrThread.getSensorMgrs().get(sensorName).isAlive()) {
            CmdMessageGrpIds send = new CmdMessageGrpIds(CmdMsgType.SENSORY_REQUEST, null, List.of(grpId));
            if (!appMgr.getRequestMap().containsKey(Channel.getSensor(sensorName))) {
                appMgr.getRequestMap().put(Channel.getSensor(sensorName), new SynchronousString());
            }
            appMgr.getRequestMap().get(Channel.getSensor(sensorName)).put(GET_SENSOR_DATA);
            Publisher.publish(Channel.getSensorRequest(sensorName), send.toString());
            value = _getSensorData.blockTake();
        }
        return value;
    }

    private String getAllSensorData(String appName) {
        JSONArray ja = new JSONArray();
        if (appName.equals("WebServer")) {
            ResMgrThread.getSensorMgrs().forEach((sensorName, sensorMgr) -> {
                JSONObject joo = new JSONObject(2);
                joo.put(SensorInfo.SENSOR_NAME_FIELD, sensorName);
                joo.put(DataField.VALUE_FIELD, getSensorData(appName, sensorName));
                ja.add(joo);
            });
        } else {
            AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
            appMgr.getSensorsName().forEach(sensorName -> {
                JSONObject joo = new JSONObject(2);
                joo.put(SensorInfo.SENSOR_NAME_FIELD, sensorName);
                joo.put(DataField.VALUE_FIELD, getSensorData(appName, sensorName));
                ja.add(joo);
            });
        }
        return ja.toJSONString();
    }

    private String getMsgThread(String appName, CmdType cmd) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (cmd == CmdType.START) {
            getMsgThreadState = true;
            appMgr.getSensors().forEach(sensorMgr -> {
                if (!sensorMgr.isGetValueRunning()) {
                    sensorMgr.startGetValue();
                }
            });
        } else if (cmd == CmdType.STOP) {
            getMsgThreadState = false;
            appMgr.getSensors().forEach(sensorMgr -> {
                if (sensorMgr.isGetValueRunning() && sensorMgr.getApps().size() == 1 && sensorMgr.getApps().contains(appMgr)) {
                    sensorMgr.stopGetValue();
                }
            });
        }
        retJson.put(DataField.STATE_FIELD, true);
        return retJson.toJSONString();
    }
    
    private String getSupportedActors() {
        JSONArray retJsonArray = new JSONArray();
        ResMgrThread.getActorMgrs().forEach((actorName, config) -> {
            retJsonArray.add(JSONObject.parse(config.toString()));
        });
        return retJsonArray.toJSONString();
    }

    private String getRegisteredActors(String appName) {
        JSONArray retJsonArray = new JSONArray();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            appMgr.getActors().forEach(config -> {
                retJsonArray.add(JSONObject.parse(config.toString()));
            });
        }
        return retJsonArray.toJSONString();
    }

    private String getRegisteredActorsStatus(String appName) {
        JSONObject retJson = new JSONObject(1);
        boolean state = true;
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            for (ActorMgr config : appMgr.getActors()) {
                if (!config.isAlive()) {
                    state = false;
                    break;
                }
            }
        } else {
            state = false;
        }

        retJson.put(DataField.STATE_FIELD, state);
        return retJson.toJSONString();
    }

    private String registerActor(String appName, String actorName) {
        JSONObject retJson = new JSONObject(1);
        Map<String, ActorMgr> actorMgrMap = ResMgrThread.getActorMgrs();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null && actorMgrMap.containsKey(actorName)) {
            ActorMgr actorMgr = actorMgrMap.get(actorName);
            appMgr.getActors().add(actorMgr);
            actorMgr.getApps().add(appMgr);
            subscribe(Channel.getActor(actorName), grpId);
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String cancelActor(String appName, String actorName) {
        JSONObject retJson = new JSONObject(1);
        Map<String, ActorMgr> actorMgrMap = ResMgrThread.getActorMgrs();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null && appMgr.getActorsName().contains(actorName)) {
            ActorMgr actorMgr = actorMgrMap.get(actorName);
            appMgr.getActors().remove(actorMgr);
            actorMgr.getApps().remove(appMgr);
            unsubscribe(Channel.getActor(actorName));
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String cancelAllActors(String appName) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        appMgr.getActorsName().forEach(actorName ->{
            cancelActor(appName, actorName);
        });
        retJson.put(DataField.STATE_FIELD, true);
        return retJson.toJSONString();
    }

    private String setActorCmd(String appName, String actorName, String action) {
        JSONObject retJson = new JSONObject(1);
        Map<String, ActorMgr> actorMgrMap = ResMgrThread.getActorMgrs();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null
                && appMgr.getActorsName().contains(actorName)
                && actorMgrMap.get(actorName).isAlive()) {
            CmdMessageGrpIds send = new CmdMessageGrpIds(CmdMsgType.ACTION_REQUEST, action, List.of(grpId));
            if (!appMgr.getRequestMap().containsKey(Channel.getActor(actorName))) {
                appMgr.getRequestMap().put(Channel.getActor(actorName), new SynchronousString());
            }
            appMgr.getRequestMap().get(Channel.getActor(actorName)).put("setActorCmd");
            Publisher.publish(Channel.getActorRequest(actorName), send.toString());
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    private String isServiceOn(String appName, ServiceType service) {
        boolean state = false;
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            switch (service) {
                case CTX:
                    state = appMgr.isCtxServerOn();
                    break;
                case INV:
                    state = appMgr.isInvServerOn();
                    break;
                case ALL:
                    state = appMgr.isCtxServerOn() && appMgr.isInvServerOn();
                    break;
            }
        }
        return "{\"state\":" + state + "}";
    }

    private String serviceCall(String appName, ServiceType service, CmdType cmd, ServiceConfig config) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr == null) {
            retJson.put(DataField.STATE_FIELD, false);
        } else {
            boolean ret = call(appMgr.getAppName(), service, cmd, config);
            retJson.put(DataField.STATE_FIELD, ret);
        }
        return retJson.toJSONString();
    }

    public String getSensorInfo(String sensorName) {
        String ret = "";
        try {
            ret = ResMgrThread.getSensorMgrs().get(sensorName).toString();
        } catch (Exception ignored) {}
        return ret;
    }

    public String getSensorInfoAndData(String sensorName) {
        String ret = "";
        try {
            SensorInfo sensorInfo = ResMgrThread.getSensorMgrs().get(sensorName).getSensorInfo();
            String sensorData = getSensorData(appMgr.getAppName(), sensorName);
            JSONObject jo = sensorInfo.toJSONObject();
            jo.put(DataField.VALUE_FIELD, sensorData);
            ret = jo.toJSONString();
        } catch (Exception ignored) {}
        return ret;
    }

    public String getAllSensorInfoAndData() {
        JSONArray ja = new JSONArray();
        ResMgrThread.getSensorMgrs().forEach((sensorName, config) -> {
            String sensorData = getSensorData(appMgr.getAppName(), sensorName);
            JSONObject jo = config.getSensorInfo().toJSONObject();
            jo.put(DataField.VALUE_FIELD, sensorData);
            ja.add(jo);
        });
        return ja.toJSONString();
    }

    public String getActorInfo(String actorName) {
        String ret = "";
        try {
            ret = ResMgrThread.getActorMgrs().get(actorName).toString();
        } catch (Exception ignored) {}
        return ret;
    }

    public String getAppInfo(String appName) {
        String ret = "";
        try {
            ret = AppMgrThread.getAppMgrs().get(appName).toString();
        } catch (Exception ignored) {}
        return ret;
    }

    public String getAllAppInfo() {
        JSONArray ja = new JSONArray();
        AppMgrThread.getAppMgrs().forEach((appName, config) -> {
            if (!appName.equals("WebServer")) {
                ja.add(JSONObject.parse(config.toString()));
            }
        });
        return ja.toJSONString();
    }

    public String getServiceInfo(String appName, ServiceType service) {
        ServiceInfo ret;
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            ret = appMgr.getServiceInfo(service);
            return ret.toString();
        }
        return "{\"service_type\":\"" + service + "\",\"app_name\":\"" + appName + "\",\"state\":\"off\"}";
    }

    public String getAllServiceInfo(ServiceType service) {
        JSONArray ja = new JSONArray();
        AppMgrThread.getAppMgrs().forEach((appName, config) -> {
            if (!appName.equals("WebServer")) {
                ja.add(config.getServiceInfo(service).toJSONObject());
            }
        });
        return ja.toJSONString();
    }

    public String dbCreate(String appName, String tableName, String primaryKey, List<String> header, int rowLimit) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJson.put(DataField.STATE_FIELD, appMgr.getDatabase().dbCreate(tableName, primaryKey, header, rowLimit));
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    public String dbDrop(String appName, String tableName) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJson.put(DataField.STATE_FIELD, appMgr.getDatabase().dbDrop(tableName));
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    public String dbInsert(String appName, String tableName, Map<String, Object> row) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJson.put(DataField.STATE_FIELD, appMgr.getDatabase().dbInsert(tableName, row));
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    public String dbUpdate(String appName, String tableName, Map<String, Object> row) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJson.put(DataField.STATE_FIELD, appMgr.getDatabase().dbUpdate(tableName, row));
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    public String dbDelete(String appName, String tableName, int row, List<Condition> conditions
            , List<Order> orders) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null && appMgr.getDatabase().dbDelete(tableName, row, conditions, orders)) {
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    public String dbDeletes(String appName, String tableName, int rows, List<Condition> conditions
            , List<Order> orders) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null && appMgr.getDatabase().dbDeletes(tableName, rows, conditions, orders)) {
            retJson.put(DataField.STATE_FIELD, true);
        } else {
            retJson.put(DataField.STATE_FIELD, false);
        }
        return retJson.toJSONString();
    }

    public String dbRow(String appName, String tableName, int row, List<String> columns, List<Condition> conditions
            , List<Order> orders) {
        JSONObject retJson = new JSONObject();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJson.putAll(appMgr.getDatabase().dbRow(tableName, row, columns, conditions, orders));
        }
        return retJson.toJSONString();
    }

    public String dbRows(String appName, String tableName, int rows, List<String> columns, List<Condition> conditions
            , List<Order> orders) {
        JSONArray retJsonArray = new JSONArray();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            appMgr.getDatabase().dbRows(tableName, rows, columns, conditions, orders).forEach(row -> {
                JSONObject jo = new JSONObject();
                jo.putAll(row);
                retJsonArray.add(jo);
            });
        }
        return retJsonArray.toJSONString();
    }

    public String dbColumn(String appName, String tableName, int rows, String column,
                           List<Condition> conditions, List<Order> orders) {
        JSONArray retJsonArray = new JSONArray();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJsonArray.addAll(appMgr.getDatabase().dbColumn(tableName, rows, column, conditions, orders));
        }
        return retJsonArray.toJSONString();
    }

    public String dbColumns(String appName, String tableName, int rows, List<String> columns,
                           List<Condition> conditions, List<Order> orders) {
        JSONObject retJson = new JSONObject();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            appMgr.getDatabase().dbColumns(tableName, rows, columns, conditions, orders).forEach((column, values) -> {
                JSONArray ja = new JSONArray();
                ja.addAll(values);
                retJson.put(column, ja);
            });
        }
        return retJson.toJSONString();
    }

    public String dbCell(String appName, String tableName, int row, String column,
                         List<Condition> conditions, List<Order> orders) {
        String ret = "@#$%";
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            ret = appMgr.getDatabase().dbCell(tableName, row, column, conditions, orders).toString();
        }
        return ret;
    }

    public String dbHeader(String appName, String tableName) {
        JSONArray retJsonArray = new JSONArray();
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJsonArray.addAll(appMgr.getDatabase().dbHeader(tableName));
        }
        return retJsonArray.toJSONString();
    }

    public String dbCount(String appName, String tableName) {
        JSONObject retJson = new JSONObject(1);
        AppMgr appMgr = AppMgrThread.getAppMgrs().get(appName);
        if (appMgr != null) {
            retJson.put("size", appMgr.getDatabase().dbCount(tableName));
        } else {
            retJson.put("size", -1);
        }
        return retJson.toJSONString();
    }

    private String monitor(String appName, JSONArray objs) {
        AppInvServer appInvServer = PlatformInvServer.getAppInvServer(appName);
        boolean ret = false;
        if (appInvServer != null) {
            ret = appInvServer.monitor(objs.toJavaList(String.class));
        }
        return "{\"state\":" + ret + "}";
    }

    private String isMonitored(String appName, JSONArray objs) {
        AppInvServer appInvServer = PlatformInvServer.getAppInvServer(appName);
        boolean ret = false;
        if (appInvServer != null) {
            ret = appInvServer.isMonitored(objs.toJavaList(String.class));
        }
        return "{\"state\":" + ret + "}";
    }

    private String check(String appName, JSONObject jo) {
        AppInvServer appInvServer = PlatformInvServer.getAppInvServer(appName);
        boolean ret = false;
        if (appInvServer != null) {
            ret = appInvServer.check(jo);
        }
        return "{\"state\":" + ret + "}";
    }

    private String save(String appName) {
        AppInvServer appInvServer = PlatformInvServer.getAppInvServer(appName);
        if (appInvServer != null) {
            JSONObject retJson = new JSONObject(1);
            retJson.put("content", appInvServer.save());
            return retJson.toJSONString();
        } else {
            return "{\"content\":\"@#$%\"}";
        }
    }

    private String load(String appName, String content) {
        try {
            AppInvServer appInvServer = PlatformInvServer.getAppInvServer(appName);
            if (appInvServer != null) {
                JSONObject retJson = new JSONObject(1);
                retJson.put(DataField.STATE_FIELD, appInvServer.load(JSON.parseObject(content)));
                return retJson.toJSONString();
            } else {
                return FAIL_STATE;
            }
        } catch (Exception e) {
            return FAIL_STATE;
        }
    }

    private String checkGenerated(String appName) {
        AppInvServer appInvServer = PlatformInvServer.getAppInvServer(appName);
        if (appInvServer != null) {
            JSONObject retJson = new JSONObject(1);
            retJson.put(DataField.STATE_FIELD, appInvServer.checkGenerated());
            return retJson.toJSONString();
        } else {
            return FAIL_STATE;
        }
    }

    private String setUI(String jspUrl, String dslFileContent) {
        if (!jspUrl.endsWith(".jsp")) {
            return FAIL_STATE;
        }
        String htmlFileName = jspUrl.replace(".jsp", ".html");
        String jspFileName = jspUrl;
        Path filePath = new File(htmlFileName).toPath();
        Util.writeFileContent(filePath, dslFileContent, "//quota");
        try {
            JSPMaker.convertHtmlFileToJspFile(htmlFileName, jspFileName);
        } catch (IOException e) {
            return FAIL_STATE;
        }
        return SUCCESS_STATE;
    }
}
